package model.directory;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import model.logic.Disjunction;
import model.types.Int;
import model.types.Nat;

public class Directory {
	
	/**
	 * list of managed services.  
	 */
	private List<Service> services;
	
	public Directory(List<Service> services) {
		this.services = services;	
	}
	
	public Directory() {
		this.services = new Vector<Service>();
		Class<?>[] innerClasses = this.getClass().getDeclaredClasses();
		for (int i = 0; i < innerClasses.length; i++) {
			Class<?> current = innerClasses[i];
			if (Service.class.isAssignableFrom(current)) {
				Constructor<?> constructor;
				try {
					constructor = current.getConstructor(new Class<?>[]{this.getClass()});
					this.services.add((Service) constructor.newInstance(this));
				} catch (SecurityException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (NoSuchMethodException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	public Object execute(List<Object>actualParameters, Disjunction postConditions, Class<?> returnType) throws ExecutionException, NotFoundException {
		Iterator<Service> i = this.getServices().iterator();
		while (i.hasNext()) {
			Service currentService = i.next();
			try {
				return currentService.execute(actualParameters, postConditions, returnType);
			} catch (NotFoundException e) {
				e = null; //Shut up, checkstyle 
				//Take next, do nothing, everything is fine 
			}
		}
		throw new NotFoundException("No suitable Method found");
	}
	/**
	 * Adds a service to this.  
	 * @param service <tt>Service</tt> to be added
	 */
	public void registerService(Service service) {
		if (!this.services.contains(service)) {
			this.services.add(service);
		}
	}
	
	private List<Service> getServices() {
		return this.services;
	}
	
	/**
	 * Service for Math-Operations. 
	 * @author Marius Tempelmeier
	 *
	 */
	@SuppressWarnings("unused")
	private class MathService extends Service {
		
		public MathService() {
			super();
			Method abs = this.getClass().getDeclaredMethods()[0];
			this.addOperation(new ServiceOperation(abs, MethodProvider.getAbsAnnotation()));
		}
		
		/**
		 * Calculates the absolute value of <tt>x</tt>. 
		 * @param x operand
		 * @return |x|
		 */
		public Nat abs(Int x) {
			return MethodProvider.abs(x);
		}
	}
}
